﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年2月19日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：选定距“当前选定的所有部件所构成的矩形”最近的一个部件。
    ///           “最近”的标准，以向左选定为例：
    ///           ⑴先看由基准部件左边与页面左边构成的目标矩形LeftRect有重叠区的部件，
    ///             ——这些部件必须尚未被选定
    ///           ⑵如果存在，则查看这些部件的左边缘或右边缘，
    ///                 若其右边缘已超出LeftRect的左边，则此部件的右边不参与比较，只比较其左边；
    ///                 若一个部件的左边或右边靠LeftRect的左边最近，则选定此部件。
    ///           如果没有同时按住Shift键，会取消原先被选定的所有部件的选定状态；否则只是增加选定。
    /// </summary>
    public static class SelectAtUpCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static SelectAtUpCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "SelectAtUpCommand",
                "SelectAtUpCommand",
                typeof(SelectAtUpCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //PageEditor pe = manager.GetMainSelectedPageEditor();
            //if (pe == null)
            //{
            //    e.CanExecute = false; return;
            //}

            e.CanExecute = true; return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute()
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";
            if (Globals.MainWindow.EditorManager == null) return "　　未找到页面管理器。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            PageEditor mainPageEditor = manager.GetMainSelectedPageEditor();
            if (mainPageEditor == null) return "　　未找到活动页面。";

            List<Widgets.Widget> selectedWidgets = mainPageEditor.GetSelectedWidgetsList();

            if (selectedWidgets.Count <= 0)
            {
                if (mainPageEditor.Children.Count > 0)
                {
                    foreach (UIElement ue in mainPageEditor.Children)
                    {
                        Widgets.Widget w = ue as Widgets.Widget;
                        if (w != null)
                        {
                            w.IsMainSelected = true; return string.Empty;//直接选定找到的第一个部件。
                        }
                    }

                    return string.Empty;//没有部件，直接返回，什么也不做。
                }
                else
                {
                    return string.Empty;//没有部件，直接返回，什么也不做。
                }
            }

            Rect baseRect;          //选定部件所构成的矩形。
            Rect destRect;          //目标区域的矩形（由baseRect的某边到页面的对应边所构成）。

            //先算出所有选定的部件所构成的baseRect
            baseRect = selectedWidgets[0].RealRect;
            for (int i = 1; i < selectedWidgets.Count; i++)//索引从1开始即可。
            {
                baseRect.Union(selectedWidgets[i].RealRect);
            }

            if (baseRect.Top <= 0) return string.Empty;//没可用区域，直接返回。

            if (baseRect.Left <= 0)
            {
                destRect = new Rect(0, 0, baseRect.Right, baseRect.Top > 0 ? baseRect.Top - 1 : 0);
            }
            else
            {
                destRect = new Rect(baseRect.Left, 0, baseRect.Width, baseRect.Top > 0 ? baseRect.Top - 1 : 0);
            }

            //先找出与目标区域有交集的部件，然后再比较这些部件的范围。
            Widgets.Widget destWidget = null;
            foreach (UIElement ue in mainPageEditor.Children)
            {
                Widgets.Widget w = ue as Widgets.Widget;
                if (w == null || w.IsSelected ||                              //不应重复选定
                    w.RealRect.IntersectsWith(destRect) == false) continue;

                if (w == destWidget) continue;

                if (destWidget == null)
                {
                    destWidget = w; continue;
                }

                if (destWidget.RealRect.Bottom > baseRect.Top)
                {
                    //比较老顶边
                    if (w.RealRect.Bottom > baseRect.Top)
                    {
                        //比较两个顶边
                        if (w.RealRect.Top > destWidget.RealRect.Top)
                        {
                            destWidget = w;
                        }
                        continue;
                    }
                    else
                    {
                        //比较新底与老顶
                        if (w.RealRect.Bottom > destWidget.RealRect.Top)
                        {
                            destWidget = w;
                        }
                        continue;
                    }
                }
                else
                {
                    //比较老底边
                    if (w.RealRect.Bottom > baseRect.Top)
                    {
                        //比较新顶边与老底边
                        if (w.RealRect.Top > destWidget.RealRect.Bottom)
                        {
                            destWidget = w;
                        }
                        continue;
                    }
                    else
                    {
                        //比较新底边与老底边
                        if (w.RealRect.Bottom > destWidget.RealRect.Bottom)
                        {
                            destWidget = w;
                        }
                        continue;
                    }
                }
            }

            if (destWidget != null)
            {
                destWidget.SelectOnlySelf();
            }
            else
            {
                List<Widgets.Widget> widgetList = mainPageEditor.GetWidgetsInArea(
                    new Rect(0, 0, mainPageEditor.ActualWidth, destRect.Bottom - 20), false);
                if (widgetList.Count > 0)
                {
                    widgetList[0].SelectOnlySelf();
                }
            }

            return string.Empty;
        }

        #endregion
    }
}
